package testgenerator;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.ArrayList;
import javax.imageio.ImageIO;

/**
 *
 * @author stussy
 */
public class TestGenerator {

    final int SQUARE = 1;
    final int CIRCLE = 2;
    /*///this should be in database - only here for demo
    ArrayList<Object> DATABASE_foreground[];// multiple foregrounds - one for each image
    ArrayList<Integer> DATABASE_percentages;
    ArrayList<Integer> DATABASE_sizes;
    int DATABASE_numberOfSizes;
    int DATABASE_gapSize;
    int DATABASE_format;//1=square  //2=circle
    int DATABASE_numberOfImages;
    int DATABASE_back_ground_colour[] = {32, 55, 49};
    int DATABASE_fore_ground_colour[] = {243, 132, 95};
    int colourset[][][] = {{{130, 170, 150}, {249, 128, 93}}, {{230, 166, 113}, {236, 170, 141}}, {{138, 129, 125}, {226, 137, 128}}};
    //{230,166,113} plate 2
    //{183, 180, 128}
    */
    final int TRY_BEFORE_STOPPING = 999999; // change this to decrease the time used to generate an image 5*9
    final int NUMBER_OF_SHADES = 2; //max of 3
    ArrayList foreground1;
    ArrayList foreground2;
    /*
     *
     */

    public TestGenerator() {
    }

    private int Total(ArrayList list) {
        int total = 0;
        for (int i = 0; i < list.size(); i++) {
            total += (Integer) list.get(i);
        }
        return total;
    }

    /**
     * Fills all whitespace in objectf with given ratio
     * @param objectf
     * @param format
     * @param percentages
     * @param sizes
     * @return
     */
    private ArrayList FillObject(BufferedImage object, int format, ArrayList percentages, ArrayList sizes, int gap, ArrayList coordinates, Color colour, boolean useShades) {
        ArrayList mySquares = new ArrayList();
        //perentages.size should be the same as sizes.size because they have a one to one ratio, and the total of all percentages should be at most 100
        if ((percentages.size() != sizes.size()) && (Total(percentages) > 100)) {
            return mySquares;
        }

        int totalSize = coordinates.size();
        Graphics2D g2 = (Graphics2D) object.createGraphics();
        int currentFormat;
        for (int i = 0; i < sizes.size(); i++) {  //for each of the different sizes shapes try to add the shape until the percentage is reached
            int size = (Integer) sizes.get(i);
            if (size < 3)//use square format if shape is very small
            {
                currentFormat = SQUARE;
            } else {
                currentFormat = format;
            }

            double sizeD = size + (gap * 2); //the shape is larger than size because of white space around it
            double area;
            if (currentFormat == SQUARE) {
                area = sizeD * sizeD;
            } else {
                area = Math.PI * (Math.pow(sizeD / 2, 2));
            }

            double y;
            y = area / (totalSize / 100);// calculate percentage of area covered by shape
            int percentageToFill = (Integer) percentages.get(i);
            double squaresToFill = percentageToFill / y;
            int squaresAdded = 0;
            Random gen = new Random();
            int missed = 0;

            Random colourGen = new Random();
            while (squaresAdded < squaresToFill && missed < TRY_BEFORE_STOPPING) {
                int temp = Math.abs(gen.nextInt(coordinates.size() - 1));
                int tx = ((Coordinates) coordinates.get(temp)).x;
                int ty = ((Coordinates) coordinates.get(temp)).y;

                int colourRand = 0;
                if (useShades) {
                    colourRand = Math.abs(colourGen.nextInt(NUMBER_OF_SHADES));
                    colourRand--;
                }
                switch (currentFormat) {
                    case SQUARE:
                        niSquare mySquare = new niSquare(tx, ty, size);
                        if (!mySquare.checkDrawSquare(gap, object, g2, colour, colourRand)) {
                            missed++;
                        } else {
                            missed = 0;
                            //add to array
                            mySquares.add(mySquare);
                            squaresAdded++;
                        }
                        break;
                    case CIRCLE:
                        niCircle myCircle = new niCircle(tx, ty, size);
                        if (!myCircle.checkDrawCircle(gap, object, g2, colour, colourRand)) {
                            missed++;
                        } else {
                            missed = 0;
                            //add to array
                            mySquares.add(myCircle);
                            squaresAdded++;
                        }
                        break;
                }
            }
            if (missed >= TRY_BEFORE_STOPPING) {
                System.out.println(TRY_BEFORE_STOPPING + " collisions");
            }
        }
        return mySquares;
    }

    /**
     * Inverts objectf to fill foreground
     * @param objectf
     * @return list of Circle/Square objects which represent the foreground
     */
    public boolean FillForeground(File objectf, int format, ArrayList percentages, ArrayList sizes, int gapSize, int numberOfForegrounds) {
        try {
            BufferedImage buff = ImageIO.read(objectf);

            if (numberOfForegrounds > 0) {
                ArrayList coordinates1 = new ArrayList();
                Invert(buff, coordinates1, 1);
                foreground1 = FillObject(buff, format, percentages, sizes, gapSize, coordinates1, Color.black, false);
                if(numberOfForegrounds==1)
                    return true;
            }

            if (numberOfForegrounds > 1) {
                ArrayList coordinates2 = new ArrayList();
                Invert(buff, coordinates2, 2);
                foreground2 = FillObject(buff, format, percentages, sizes, gapSize, coordinates2, Color.black, false);
                if(numberOfForegrounds==2)//?
                    return true;
                else
                    return false;
            }
            //return foreground1;
        } catch (IOException e) {
            //objectf file not found?
        }
        return false;
        //return null;
    }

    /*
     * @param object - An ArrayList of niSquare or niCircle objects representing the foreground of the image - retrieved with fillObject()
     * @param format - 1 = squares, 2 = circles
     * @param percentages
     * @param sizes
     * @param gapSize
     * @param foregroundColour
     * @param backgroundColour
     * @return A BufferedImage object of the final NiSee image
     */
    public BufferedImage CreateImage(ArrayList foreground1, ArrayList foreground2, int format, ArrayList percentages, ArrayList sizes, int gapSize, Color foregroundColour1, Color foregroundColour2, Color backgroundColour) {
        try {
            //get a blank image
            File f1 = new File("blank.JPG");
            BufferedImage bufferedImage = ImageIO.read(f1);

            if (foreground1 != null) {
                if ((foreground1.size() > 0) && (foregroundColour1 != null)) {
                    AddForeground(foreground1, format, foregroundColour1, bufferedImage);
                }
            }
            if (foreground2 != null) {
                if ((foreground2.size() > 0) && (foregroundColour2 != null)) {
                    AddForeground(foreground2, format, foregroundColour2, bufferedImage);
                }
            }

            //get ArrayList of valid coordinates
            ArrayList coordinates = getCoordinates(bufferedImage);

            FillObject(bufferedImage, format, percentages, sizes, gapSize, coordinates, backgroundColour, true);
            return bufferedImage;
        } catch (IOException ex) {
            System.out.println("Is the current directory set to point to Repository/Source?");
            System.out.println("ERROR in CreateImage():" + ex.toString());
        }
        return null;
    }

    private void AddForeground(ArrayList foreground, int format, Color foregroundColour, BufferedImage img) {
        Graphics2D g2 = (Graphics2D) img.createGraphics();
        g2.setColor(Color.BLACK);
        Random colourGen = new Random();
        int colourRand;
        switch (format) {
            case SQUARE:
                for (int i = 0; i < foreground.size() - 1; i++) {
                    colourRand = Math.abs(colourGen.nextInt(NUMBER_OF_SHADES));
                    colourRand--;
                    ((niSquare) foreground.get(i)).setColour(foregroundColour);
                    ((niSquare) foreground.get(i)).drawSquare(g2, colourRand);
                }
                break;
            case CIRCLE:
                for (int i = 0; i < foreground.size() - 1; i++) {
                    colourRand = Math.abs(colourGen.nextInt(NUMBER_OF_SHADES));
                    colourRand--;
                    ((niCircle) foreground.get(i)).setColour(foregroundColour);
                    ((niCircle) foreground.get(i)).drawCircle(g2, colourRand);
                }
                break;
        }
    }

    private static void Invert(BufferedImage tshape, ArrayList coordinates, int foregroundNum) {
        for (int i = 0; i < tshape.getWidth(); i++) {
            for (int j = 0; j < tshape.getHeight(); j++) {
                if (foregroundNum == 1) {
                    if (tshape.getRGB(i, j) == Color.black.getRGB()) {
                        coordinates.add(new Coordinates(i, j));
                        tshape.setRGB(i, j, Color.white.getRGB());
                    } else {
                        if (tshape.getRGB(i, j) == Color.white.getRGB()) {
                            tshape.setRGB(i, j, Color.black.getRGB());
                        }
                    }
                } else {
                    if ((tshape.getRGB(i, j) != Color.black.getRGB()) && ((tshape.getRGB(i, j) != Color.white.getRGB()))) {
                        coordinates.add(new Coordinates(i, j));
                        tshape.setRGB(i, j, Color.white.getRGB());
                        //tshape.setRGB(i, j, Color.black.getRGB());
                    } else {
                        tshape.setRGB(i, j, Color.black.getRGB());
                        //System.out.println("Should not be here");
                    }
                }
            }
        }

        /*for (int i = 0; i < tshape.getWidth(); i++) {
        for (int j = 0; j < tshape.getHeight(); j++) {
        tshape.setRGB(i, j, Color.black.getRGB());
        }

        }*/

        /*for (int i = 0; i < coordinates.size(); i++) {
        tshape.setRGB(((Coordinates) coordinates.get(i)).x, ((Coordinates) coordinates.get(i)).y, Color.white.getRGB());
        }*/
    }

    private static ArrayList getCoordinates(BufferedImage tshape) {
        ArrayList coordinates = new ArrayList();
        for (int i = 0; i < tshape.getWidth(); i++) {
            for (int j = 0; j < tshape.getHeight(); j++) {
                if (tshape.getRGB(i, j) == Color.white.getRGB()) {
                    coordinates.add(new Coordinates(i, j));
                }

            }
        }
        return coordinates;
    }
}
